using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using GenesisCore;

namespace GenesisWindows
{
	/// <summary>
	/// This is the main type for your game
	/// </summary>
	public class Main : Microsoft.Xna.Framework.Game
	{
		private const int FPS = 60;
		GraphicsDeviceManager m_graphics;

		Texture2D m_targetTexture;
		SpriteBatch m_spriteBatch;

		Genesis m_Genesis = new Genesis();
		bool m_Running;

		public Main()
		{
			this.TargetElapsedTime = new TimeSpan(10000000 / FPS);

			Content.RootDirectory = "Content";

			m_graphics = new GraphicsDeviceManager(this);

			this.LoadRom(@"D:\SegaRoms\GODS.ZIP");
		}

		private void LoadRom(string fileName)
		{
			this.m_Genesis.LoadRom(fileName);
			this.Window.Title = "Sega360 - " + this.m_Genesis.RomName;

			this.m_Running = true;
		}

		/// <summary>
		/// Allows the game to perform any initialization it needs to before starting to run.
		/// This is where it can query for any required services and load any non-graphic
		/// related content.  Calling base.Initialize will enumerate through any components
		/// and initialize them as well.
		/// </summary>
		protected override void Initialize()
		{
			// TODO: Add your initialization logic here
			base.Initialize();

			m_graphics.PreferredBackBufferWidth = 640;
			m_graphics.PreferredBackBufferHeight = 448;
			m_graphics.ApplyChanges();
		}

		/// <summary>
		/// LoadContent will be called once per game and is the place to load
		/// all of your content.
		/// </summary>
		protected override void LoadContent()
		{
			// Create a new SpriteBatch, which can be used to draw textures.
			this.m_spriteBatch = new SpriteBatch(GraphicsDevice);

			// TODO: use this.Content to load your game content here
			this.m_targetTexture = new Texture2D(m_graphics.GraphicsDevice, 320, 224, 1, TextureUsage.None,
				SurfaceFormat.Bgr32);
		}

		/// <summary>
		/// UnloadContent will be called once per game and is the place to unload
		/// all content.
		/// </summary>
		protected override void UnloadContent()
		{
			// TODO: Unload any non ContentManager content here
		}

		/// <summary>
		/// Allows the game to run logic such as updating the world,
		/// checking for collisions, gathering input, and playing audio.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Update(GameTime gameTime)
		{
			// Get keyboard/gamepad state
			KeyboardState keyboardState = Keyboard.GetState();
			this.m_Genesis.SetGamepad(0,
				keyboardState.IsKeyDown(Keys.Up),
				keyboardState.IsKeyDown(Keys.Down),
				keyboardState.IsKeyDown(Keys.Left),
				keyboardState.IsKeyDown(Keys.Right),
				keyboardState.IsKeyDown(Keys.A),
				keyboardState.IsKeyDown(Keys.S),
				keyboardState.IsKeyDown(Keys.D),
				keyboardState.IsKeyDown(Keys.Enter));

			if (keyboardState.IsKeyDown(Keys.Back))
			{
				this.Exit();
			}

			this.m_Genesis.UpdateFrame();

			base.Update(gameTime);
		}

		/// <summary>
		/// This is called when the game should draw itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Draw(GameTime gameTime)
		{
			m_graphics.GraphicsDevice.Clear(Color.Black);

			if (m_Running)
			{
				m_targetTexture.GraphicsDevice.Textures[0] = null;
				m_targetTexture.SetData<uint>(this.m_Genesis.FrameBuffer, 0,
				 320 * 224, SetDataOptions.None);

				m_spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
				m_graphics.GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.None;
				m_spriteBatch.Draw(m_targetTexture, new Rectangle(0, 0,
					640, 448), Color.White);

				m_spriteBatch.End();
			}

			base.Draw(gameTime);
		}
	}
}
